import tkinter as tk
from tkinter import filedialog, ttk, scrolledtext, messagebox
import exifread
from PIL import Image, ImageTk, ImageDraw, ImageFont
from PIL.ExifTags import TAGS, GPSTAGS
import os
import sys
import json
import xml.etree.ElementTree as ET
from xml.dom import minidom
import datetime
import threading

class ExifViewerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("照片EXIF查看器及水印添加V0.2")
        self.root.geometry("800x600")
        self.root.resizable(True, True)

        # 设置中文字体支持
        self.font_family = ("SimHei", "WenQuanYi Micro Hei", "Heiti TC", "Arial")
        self.font_size = 10

        # 缩放因子，适配不同分辨率
        self.scaling_factor = self.root.tk.call('tk', 'scaling')
        if self.scaling_factor < 1.0:
            self.scaling_factor = 1.0

        # 创建主框架
        self.main_frame = ttk.Frame(self.root, padding=10)
        self.main_frame.pack(fill=tk.BOTH, expand=True)

        # 顶部控制区
        self.control_frame = ttk.Frame(self.main_frame)
        self.control_frame.pack(fill=tk.X, pady=(0, 10))

        # 选择图片按钮
        self.select_btn = ttk.Button(
            self.control_frame,
            text="选择图片",
            command=self.select_image,
            style='TButton'
        )
        self.select_btn.pack(side=tk.LEFT, padx=(0, 10))

        # 添加水印按钮
        self.watermark_btn = ttk.Button(
            self.control_frame,
            text="添加水印",
            command=lambda: self.add_watermark_to_image(self.image_path_var.get()),
            style='TButton'
        )
        self.watermark_btn.pack(side=tk.LEFT, padx=(0, 10))

        # 图片路径显示
        self.image_path_var = tk.StringVar()
        self.image_path_entry = ttk.Entry(
            self.control_frame,
            textvariable=self.image_path_var,
            width=50
        )
        self.image_path_entry.pack(side=tk.LEFT, fill=tk.X, expand=True)

        # 分割线
        ttk.Separator(self.main_frame).pack(fill=tk.X, pady=(0, 10))

        # 创建标签页控件
        self.tab_control = ttk.Notebook(self.main_frame)
        self.tab_control.pack(fill=tk.BOTH, expand=True)

        # EXIF信息标签页
        self.exif_tab = ttk.Frame(self.tab_control)
        self.tab_control.add(self.exif_tab, text="EXIF信息")

        # 图片预览标签页
        self.preview_tab = ttk.Frame(self.tab_control)
        self.tab_control.add(self.preview_tab, text="图片预览")

        # 水印预览标签页
        self.watermark_preview_tab = ttk.Frame(self.tab_control)
        self.tab_control.add(self.watermark_preview_tab, text="水印预览")

        # 创建EXIF信息显示区域
        self.exif_text = scrolledtext.ScrolledText(
            self.exif_tab,
            wrap=tk.WORD,
            font=(self.font_family[0], int(self.font_size * self.scaling_factor))
        )
        self.exif_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)

        # 创建图片预览区域
        self.preview_label = ttk.Label(self.preview_tab, text="选择图片后显示预览")
        self.preview_label.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)

        # 创建水印预览区域
        self.watermark_preview_label = ttk.Label(self.watermark_preview_tab, text="选择图片后显示水印预览")
        self.watermark_preview_label.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)

        # 状态栏
        self.status_var = tk.StringVar()
        self.status_var.set("就绪")
        self.status_bar = ttk.Label(
            self.root,
            textvariable=self.status_var,
            relief=tk.SUNKEN,
            anchor=tk.W
        )
        self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)

    def select_image(self):
        """选择图片文件并解析EXIF信息"""
        file_path = filedialog.askopenfilename(
            filetypes=[
                ("图片文件", "*.jpg *.jpeg *.png *.gif *.bmp *.tiff"),
                ("所有文件", "*.*")
            ]
        )

        if not file_path:
            return

        self.image_path_var.set(file_path)
        self.status_var.set(f"正在解析 {os.path.basename(file_path)} 的EXIF信息...")
        self.root.update_idletasks()

        try:
            # 解析EXIF信息
            exif_data = self.parse_exif(file_path)

            # 显示EXIF信息
            self.display_exif(exif_data)

            # 显示图片预览
            self.display_preview(file_path)

            # 显示水印预览
            self.display_watermark_preview(file_path)

            self.status_var.set(f"已加载 {os.path.basename(file_path)}")
        except Exception as e:
            self.exif_text.delete(1.0, tk.END)
            self.exif_text.insert(tk.END, f"解析EXIF信息时出错: {str(e)}")
            self.status_var.set("解析失败")

    def get_exif_maker(self, file_path):
        """提取图片EXIF信息中的制造商(maker)"""
        with open(file_path, 'rb') as f:
            tags = exifread.process_file(f)
            maker_tag = 'Image Make'
            if maker_tag in tags:
                return str(tags[maker_tag]).strip()
        return None

    def get_exif_model(self, file_path):
        """提取图片EXIF信息中的型号(model)"""
        with open(file_path, 'rb') as f:
            tags = exifread.process_file(f)
            model_tag = 'Image Model'
            if model_tag in tags:
                return str(tags[model_tag]).strip()
        return None

    def get_capture_date(self, file_path):
        """提取图片的拍摄日期"""
        with open(file_path, 'rb') as f:
            tags = exifread.process_file(f)
            # 尝试常见的日期标签
            date_tags = ["EXIF DateTimeOriginal", "EXIF DateTimeDigitized", "Image DateTime"]
            for tag in date_tags:
                if tag in tags:
                    return str(tags[tag])
        return "未知日期"

    def parse_exif(self, file_path):
        """使用exifread库解析图片的EXIF信息"""
        with open(file_path, 'rb') as f:
            tags = exifread.process_file(f)
        return tags

    def add_watermark_to_image(self, file_path):
        """为当前图片添加水印并保存"""
        if not file_path:
            self.status_var.set("请先选择一张图片")
            return

        try:
            # 获取制造商信息
            maker = self.get_exif_maker(file_path)
            if not maker:
                maker = "未知制造商"

            # 获取型号信息
            model = self.get_exif_model(file_path)
            if model:
                maker = f"{maker} {model}"  # 将model添加到maker后面

            # 获取拍摄日期
            capture_date = self.get_capture_date(file_path)

            # 让用户选择保存路径
            output_path = filedialog.asksaveasfilename(
                defaultextension=".jpg",
                filetypes=[
                    ("JPEG图片", "*.jpg"),
                    ("PNG图片", "*.png"),
                    ("所有文件", "*.*")
                ],
                initialfile=f"{os.path.splitext(os.path.basename(file_path))[0]}_watermarked.jpg"
            )

            if not output_path:
                return

            # 添加水印
            with Image.open(file_path).convert("RGBA") as img:
                draw = ImageDraw.Draw(img)
                width, height = img.size

                # 设置水印字体和大小
                font_size = int(min(width, height) * 0.05)  # 图片最小边的5%

                # 尝试加载系统字体，支持中文显示
                try:
                    # 尝试不同系统的常见字体路径
                    font_paths = [
                        "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc",  # Linux
                        "/System/Library/Fonts/PingFang.ttc",  # macOS
                        "C:\\Windows\\Fonts\\simhei.ttf",  # Windows
                        "/usr/share/fonts/truetype/freefont/FreeSans.ttf"  # 通用后备
                    ]
                    font = None
                    for path in font_paths:
                        try:
                            font = ImageFont.truetype(path, font_size)
                            break
                        except:
                            continue
                    if not font:
                        font = ImageFont.load_default()
                except:
                    font = ImageFont.load_default()

                # 计算文本尺寸
                bbox = draw.textbbox((0, 0), maker, font=font)
                text_width = bbox[2] - bbox[0]
                text_height = bbox[3] - bbox[1]

                # 设置行间距
                line_spacing = int(text_height * 0.3)  # 行间距为文本高度的30%

                # 设置水印位置（左下角，带边距）
                margin = int(min(width, height) * 0.02)  # 边距为图片最小边的2%
                x = margin
                # 计算总文本高度（两行文本 + 行间距）
                total_text_height = text_height * 2 + line_spacing
                y = height - total_text_height - margin

                # 添加半透明白色水印（带轻微黑色描边增加可读性）
                # 添加制造商水印（带描边）
                # 描边
                draw.text((x-1, y-1), maker, font=font, fill=(0, 0, 0, 100))
                draw.text((x+1, y-1), maker, font=font, fill=(0, 0, 0, 100))
                draw.text((x-1, y+1), maker, font=font, fill=(0, 0, 0, 100))
                draw.text((x+1, y+1), maker, font=font, fill=(0, 0, 0, 100))
                # 主文本
                draw.text((x, y), maker, font=font, fill=(255, 255, 255, 200))

                # 计算日期文本位置（制造商下方）
                date_y = y + text_height + line_spacing

                # 添加日期水印（带描边）
                # 描边
                draw.text((x-1, date_y-1), capture_date, font=font, fill=(0, 0, 0, 100))
                draw.text((x+1, date_y-1), capture_date, font=font, fill=(0, 0, 0, 100))
                draw.text((x-1, date_y+1), capture_date, font=font, fill=(0, 0, 0, 100))
                draw.text((x+1, date_y+1), capture_date, font=font, fill=(0, 0, 0, 100))
                # 主文本
                draw.text((x, date_y), capture_date, font=font, fill=(255, 255, 255, 200))

                # 转换回RGB模式并保存
                img.convert("RGB").save(output_path, quality=95)

            self.status_var.set(f"水印已添加并保存到: {output_path}")
        except Exception as e:
            self.status_var.set(f"添加水印时出错: {str(e)}")

    def display_exif(self, exif_data):
        """在文本区域显示EXIF信息"""
        self.exif_text.delete(1.0, tk.END)

        if not exif_data:
            self.exif_text.insert(tk.END, "未找到EXIF信息")
            return

        # 分类显示EXIF信息
        self.exif_text.insert(tk.END, "=== 图片基本信息 ===\n")
        for tag in exif_data:
            if tag.startswith('Image '):
                self.exif_text.insert(tk.END, f"{tag}: {exif_data[tag]}\n")

        self.exif_text.insert(tk.END, "\n=== 相机信息 ===\n")
        for tag in exif_data:
            if tag.startswith('EXIF '):
                self.exif_text.insert(tk.END, f"{tag}: {exif_data[tag]}\n")

        self.exif_text.insert(tk.END, "\n=== GPS信息 ===\n")
        has_gps = False
        for tag in exif_data:
            if tag.startswith('GPS '):
                self.exif_text.insert(tk.END, f"{tag}: {exif_data[tag]}\n")
                has_gps = True
        if not has_gps:
            self.exif_text.insert(tk.END, "未找到GPS信息\n")

    def display_preview(self, file_path):
        """显示图片预览"""
        try:
            # 打开图片并调整大小以适应预览区域
            image = Image.open(file_path)
            width, height = image.size

            # 计算预览尺寸，保持宽高比
            max_width = 700
            max_height = 400
            ratio = min(max_width/width, max_height/height)
            new_width = int(width * ratio)
            new_height = int(height * ratio)

            # 调整图片大小
            image = image.resize((new_width, new_height), Image.LANCZOS)

            # 转换为Tkinter可用的图片格式
            photo = ImageTk.PhotoImage(image)

            # 更新预览标签
            self.preview_label.config(image=photo)
            self.preview_label.image = photo  # 保持引用避免垃圾回收
        except Exception as e:
            self.preview_label.config(text=f"无法显示预览: {str(e)}")

    def display_watermark_preview(self, file_path):
        """显示水印预览"""
        try:
            # 获取制造商信息
            maker = self.get_exif_maker(file_path)
            if not maker:
                maker = "未知制造商"

            # 获取型号信息
            model = self.get_exif_model(file_path)
            if model:
                maker = f"{maker} {model}"  # 将model添加到maker后面

            # 获取拍摄日期
            capture_date = self.get_capture_date(file_path)

            # 打开图片并调整大小以适应预览区域
            image = Image.open(file_path).convert("RGBA")
            width, height = image.size

            # 计算预览尺寸，保持宽高比
            max_width = 700
            max_height = 400
            ratio = min(max_width/width, max_height/height)
            new_width = int(width * ratio)
            new_height = int(height * ratio)

            # 调整图片大小
            image = image.resize((new_width, new_height), Image.LANCZOS)

            # 添加水印到预览图
            draw = ImageDraw.Draw(image)
            width, height = image.size

            # 设置水印字体和大小
            font_size = int(min(width, height) * 0.05)  # 图片最小边的5%

            # 尝试加载系统字体，支持中文显示
            try:
                # 尝试不同系统的常见字体路径
                font_paths = [
                    "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc",  # Linux
                    "/System/Library/Fonts/PingFang.ttc",  # macOS
                    "C:\\Windows\\Fonts\\simhei.ttf",  # Windows
                    "/usr/share/fonts/truetype/freefont/FreeSans.ttf"  # 通用后备
                ]
                font = None
                for path in font_paths:
                    try:
                        font = ImageFont.truetype(path, font_size)
                        break
                    except:
                        continue
                if not font:
                    font = ImageFont.load_default()
            except:
                font = ImageFont.load_default()

            # 计算文本尺寸
            bbox = draw.textbbox((0, 0), maker, font=font)
            text_width = bbox[2] - bbox[0]
            text_height = bbox[3] - bbox[1]

            # 设置行间距
            line_spacing = int(text_height * 0.3)  # 行间距为文本高度的30%

            # 设置水印位置（左下角，带边距）
            margin = int(min(width, height) * 0.02)  # 边距为图片最小边的2%
            x = margin
            # 计算总文本高度（两行文本 + 行间距）
            total_text_height = text_height * 2 + line_spacing
            y = height - total_text_height - margin

            # 添加半透明白色水印（带轻微黑色描边增加可读性）
            # 添加制造商水印（带描边）
            # 描边
            draw.text((x-1, y-1), maker, font=font, fill=(0, 0, 0, 100))
            draw.text((x+1, y-1), maker, font=font, fill=(0, 0, 0, 100))
            draw.text((x-1, y+1), maker, font=font, fill=(0, 0, 0, 100))
            draw.text((x+1, y+1), maker, font=font, fill=(0, 0, 0, 100))
            # 主文本
            draw.text((x, y), maker, font=font, fill=(255, 255, 255, 200))

            # 计算日期文本位置（制造商下方）
            date_y = y + text_height + line_spacing

            # 添加日期水印（带描边）
            # 描边
            draw.text((x-1, date_y-1), capture_date, font=font, fill=(0, 0, 0, 100))
            draw.text((x+1, date_y-1), capture_date, font=font, fill=(0, 0, 0, 100))
            draw.text((x-1, date_y+1), capture_date, font=font, fill=(0, 0, 0, 100))
            draw.text((x+1, date_y+1), capture_date, font=font, fill=(0, 0, 0, 100))
            # 主文本
            draw.text((x, date_y), capture_date, font=font, fill=(255, 255, 255, 200))

            # 转换为Tkinter可用的图片格式
            photo = ImageTk.PhotoImage(image)

            # 更新水印预览标签
            self.watermark_preview_label.config(image=photo)
            self.watermark_preview_label.image = photo  # 保持引用避免垃圾回收
        except Exception as e:
            self.watermark_preview_label.config(text=f"无法显示水印预览: {str(e)}")

def main():
    # 检查是否安装了必要的库
    try:
        import exifread
    except ImportError:
        print("请安装exifread库: pip install exifread")
        sys.exit(1)

    try:
        from PIL import Image, ImageTk
    except ImportError:
        print("请安装Pillow库: pip install Pillow")
        sys.exit(1)

    # 创建并运行应用
    root = tk.Tk()
    app = ExifViewerApp(root)
    root.mainloop()

if __name__ == '__main__':
    main()